#include "Os.h"
#include "os_timer.h"
#include "cloud_helper.h"

#define TIMER_LIST_SIZE     10

typedef struct os_timer
{
    os_time_t interval;
    os_time_t start_time;
    os_timer_func_t func;
    void *param;
    uint8_t flags;
} timer_list_item_t;

typedef struct timer_list
{
    mlist_t list;
    uint8_t used[TIMER_LIST_SIZE];
    timer_list_item_t items[TIMER_LIST_SIZE];
} timer_list_t;

static volatile os_time_t g_nettime;
static volatile os_time_t g_systime;
static timer_list_t g_timer_list;
extern volatile uint32_t g_LwIPLocalTime;

static uint8_t _timer_list_foreach(void *item, mlist_list_size_t index)
{
    uint8_t i_state;
    timer_list_item_t *timer = (timer_list_item_t *)item;

    if(timer->flags & OS_TIMER_FLAG_IMME)
    {
        timer->flags &= ~OS_TIMER_FLAG_IMME;
        goto execute;
    }

    if(OS_SYSTIME_BEYOND_SPAN(timer->start_time, timer->interval))
    {
        goto execute;
    }

    return 0;
execute:
    timer->func(timer->param);
    OS_ENTER_CRITICAL(i_state);
    timer->start_time = os_timer_get_systime();
    OS_EXIT_CRITICAL(i_state);
    if(!(timer->flags & OS_TIMER_FLAG_REPEAT))
    {
        OS_ENTER_CRITICAL(i_state);
        mlist_del(&g_timer_list.list, index);
        OS_EXIT_CRITICAL(i_state);
    }

    return 1;
}

void os_timer_init()
{
    mlist_init(&g_timer_list.list, g_timer_list.used, g_timer_list.items, TIMER_LIST_SIZE, sizeof(timer_list_item_t));
}

void os_timer_poll()
{
    mlist_foreach(&g_timer_list.list, _timer_list_foreach);
}

os_timer_t os_timer_set(os_timer_func_t func, os_time_t interval, void *param, uint8_t flags)
{
    uint8_t i_state;
    mlist_list_size_t index;
    timer_list_item_t *timer;
    OS_ENTER_CRITICAL(i_state);
    index = mlist_add(&g_timer_list.list, NULL, 0);
    if(index < 0)
    {
        //os_log("timer list is full.");
        goto ret;
    }

    timer = mlist_get(&g_timer_list.list, index);
    timer->func = func;
    timer->interval = interval;
    timer->flags = flags;
    timer->param = param;
    timer->start_time = os_timer_get_systime();

ret:
    OS_EXIT_CRITICAL(i_state);
    return index;
}

uint8_t os_timer_is_valid(os_timer_t timer)
{
    return (mlist_get(&g_timer_list.list, timer) != NULL);
}

void os_timer_reset(os_timer_t timer)
{
    timer_list_item_t *timer_item;
    timer_item = mlist_get(&g_timer_list.list, timer);
    if(timer_item)
    {
        timer_item->start_time = os_timer_get_systime();
    }
}

void os_timer_del(os_timer_t timer)
{
    uint8_t i_state;
    OS_ENTER_CRITICAL(i_state);
    mlist_del(&g_timer_list.list, timer);
    OS_EXIT_CRITICAL(i_state);
}

void os_timer_pass_ms()
{
    g_systime++;
    g_nettime++;
    g_LwIPLocalTime++;

	ch_timer_ms();
}

os_time_t os_timer_get_systime()
{
    uint8_t i_state;
    os_time_t ret;

    OS_ENTER_CRITICAL(i_state);
    ret = g_systime;
    OS_EXIT_CRITICAL(i_state);
    return ret;
}

os_time_t os_timer_get_nettime()
{
    uint8_t i_state;
    os_time_t ret;

    OS_ENTER_CRITICAL(i_state);
    ret = g_nettime;
    OS_EXIT_CRITICAL(i_state);
    return ret;
}

void os_timer_add_systime(os_time_t time)
{
    uint8_t i_state;
    OS_ENTER_CRITICAL(i_state);
    g_systime += time;
    g_nettime += time;
    OS_EXIT_CRITICAL(i_state);
}

void os_timer_set_nettime(os_time_t time)
{
    uint8_t i_state;
    OS_ENTER_CRITICAL(i_state);
    g_nettime = time;
    OS_EXIT_CRITICAL(i_state);
}

os_time_t os_timer_get_interval(os_timer_t timer)
{
    timer_list_item_t *timer_item;
    timer_item = mlist_get(&g_timer_list.list, timer);
    return timer_item->interval;
}
